package com.fastloan.mgt.postloan.service.impl;

import com.fastloan.common.BasicServiceImpl;
import com.fastloan.mgt.application.base.enums.ApplicationStatusEnum;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.postloan.constants.ConstantTime;
import com.fastloan.mgt.postloan.dao.ZyPostLoanMonitorMapper;
import com.fastloan.mgt.postloan.dao.ZyPostloanFileMapper;
import com.fastloan.mgt.postloan.enums.PostLoanEnums;
import com.fastloan.mgt.postloan.model.ZyPostloanFile;
import com.fastloan.mgt.postloan.model.vo.PostLoanMonitorExt;
import com.fastloan.mgt.postloan.service.ZyPostLoanMonitorService;
import com.fastloan.mgt.postloan.model.ZyPostLoanMonitor;
import com.fastloan.mgt.product.postloan.model.ProductPostLoan;
import com.fastloan.mgt.product.postloan.model.vo.AppMonitor;
import com.fastloan.utils.ObjUtil;
import com.github.pagehelper.PageHelper;
import com.kawins.supers.file.IFileManager;
import com.kawins.supers.file.core.FileLoadBean;
import com.kawins.supers.table.manager.DataTable;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author gelon createTime 2017/11/16
 */
@org.springframework.stereotype.Service
public class ZyPostLoanMonitorServiceImpl extends BasicServiceImpl<ZyPostLoanMonitor> implements
    ZyPostLoanMonitorService {

    @org.springframework.beans.factory.annotation.Autowired
    private ZyPostLoanMonitorMapper zyPostLoanMonitorMapper;

    @Autowired
    ApplicationService applicationService;

    @Autowired
    ZyPostloanFileMapper postloanFileMapper;

    @Autowired
    IFileManager fileManager;


    /**
     * 定时任务中查询对象一次查询的条数
     */
    public static final int PAGE_SIZE = 100;


    /**
     * 扫描贷后
     */
    @Override
    @Transactional
    public void scanLoanByApplication() {
        LocalDate localDate = new LocalDate();
        scanLoan(localDate); //贷后进件维护
    }

    /**
     * 保存或者更新一个手动的贷后
     */
    @Override
    @Transactional
    public ZyPostLoanMonitor saveUpdatePostloan(ZyPostLoanMonitor zyPostLoanMonitor) {
        if (ObjUtil.isEmpty(zyPostLoanMonitor.getId())) {
            zyPostLoanMonitor
                .setPostLoanMonitorSetupType(PostLoanEnums.SetupType.MANUAL.getCode())
                .setImplementTime(new Date())
                .setCreateTime(new Date());
            zyPostLoanMonitorMapper.insertSelective(zyPostLoanMonitor);
        } else {
            zyPostLoanMonitorMapper.updateByPrimaryKeySelective(zyPostLoanMonitor);
        }
        return zyPostLoanMonitor;
    }

    /**
     * 保存或者更新贷后文件   postloanId == NULL 保存,否则更新
     */
    @Override
    @Transactional
    public ZyPostLoanMonitor saveUpdatePostloanFile(String appId, String postloanId,
        MultipartFile file) {
        if (file == null || file.getSize() == 0) {
            return null;
        }
        ZyPostLoanMonitor postLoanMonitor;
        if (ObjUtil.isEmpty(postloanId)) {
            if (ObjUtil.isEmpty(appId)) {
                return null;
            }
            postLoanMonitor = new ZyPostLoanMonitor()
                .setApplicationId(appId)
                .setPostLoanMonitorSetupType(PostLoanEnums.SetupType.MANUAL.getCode())
                .setImplementTime(new Date())
                .setCreateTime(new Date());
            zyPostLoanMonitorMapper.insertSelective(postLoanMonitor);
        } else {
            postLoanMonitor = zyPostLoanMonitorMapper.selectByPrimaryKey(postloanId);
        }
        if (postLoanMonitor == null) {
            return null;
        }
        FileLoadBean fileLoadBean = fileManager.upload(file);
        postloanFileMapper.insertSelective(new ZyPostloanFile()
            .setPostLoanId(postLoanMonitor.getId())
            .setFileId((String) fileLoadBean.getFileId()));
        return postLoanMonitor;
    }

    /**
     * 获取客户经理下进件的贷后实施信息
     */
    @Override
    @DataTable(name = "queryPostloan")
    public List<PostLoanMonitorExt> queryPostloan(Map<String, Object> map) {
        return postloanFileMapper.queryPostloan(map);
    }

    /**
     * 更新贷后
     */
    @Override
    @Transactional
    public void uploadPostloan(ZyPostLoanMonitor postLoanMonitor, MultipartFile[] files) {
        zyPostLoanMonitorMapper.updateByPrimaryKeySelective(postLoanMonitor);
        if (files == null || files.length == 0) {
            return;
        }
        Arrays.stream(files)
            .filter(file -> file.getSize() > 0 && !ObjUtil.isEmpty(file.getOriginalFilename()))
            .map(file -> fileManager.upload(file))
            .forEach(fileLoadBean -> postloanFileMapper.insertSelective(
                new ZyPostloanFile().setFileId((String) fileLoadBean.getFileId())
                    .setPostLoanId(postLoanMonitor.getId())));
    }


    /**
     * 扫描维护贷后  定时任务
     */
    private void scanLoan(LocalDate localDate) {
        int pageCount = getLoanApplicationPageCount(); //贷后进件数
        for (int i = 1; i <= pageCount; i++) { //分批读取插入
            PageHelper.startPage(i, PAGE_SIZE);
            List<AppMonitor> appMonitors = zyPostLoanMonitorMapper.queryApploanMonitor();
            for (AppMonitor appMonitor : appMonitors) {
                // 检测并尝试插入当前时间段的  首次贷后 一般贷后  实地回访记录
                ifNotFirstMonitorInsert(localDate, appMonitor);
                ifNotAfterMonitorInsert(localDate, appMonitor);
//                ifNotSiteVisibleInsert(localDate, appMonitor);
            }
        }
    }

//    private void ifNotSiteVisibleInsert(LocalDate currDate, AppMonitor appMonitor) {
//        ZyPostLoanMonitor siteVisiableMonitor = getPostLoanSiteVisiable(currDate, appMonitor); //贷后实地回访
//        List<PostLoanMonitor> siteVisiableMonitorList = postLoanMonitorMapper.select(siteVisiableMonitor);
//        if(siteVisiableMonitorList == null || siteVisiableMonitorList.size() == 0 ){//没有当前时段对应的维护信息则插入
//            siteVisiableMonitor.setPostLoanImplementResult(PostLoanImplementResult.UNFINISH.getType());
//            postLoanMonitorMapper.insertSelective(siteVisiableMonitor);
//            addDaily(siteVisiableMonitor);
//        }
//    }

    /**
     * 不存在首次贷后则添加
     */
    private void ifNotFirstMonitorInsert(LocalDate localDate, AppMonitor appMonitor) {
        ZyPostLoanMonitor postLoanMonitor = getFirstPostLoanMonitor(localDate, appMonitor); //贷后监控
        if (postLoanMonitor == null) { //不在时间段不需要检测插入
            return;
        }
        List<ZyPostLoanMonitor> postLoanMonitors = zyPostLoanMonitorMapper.select(postLoanMonitor);
        if (postLoanMonitors == null || postLoanMonitors.size() == 0) { //没有当前时段对应的维护信息则插入
            postLoanMonitor
                .setPostLoanImplementResult(PostLoanEnums.ImplementResult.UNFINISH.getCode());
            zyPostLoanMonitorMapper.insertSelective(postLoanMonitor);
        }
    }

    /**
     * 不存在正常贷后则添加
     */
    private void ifNotAfterMonitorInsert(LocalDate currDate, AppMonitor appMonitor) {
        ZyPostLoanMonitor postLoanMonitor = getAfterPostLoanMonitor(currDate, appMonitor); //贷后监控
        if (postLoanMonitor == null) { //不在时间段不需要检测插入
            return;
        }
        List<ZyPostLoanMonitor> postLoanMonitors = zyPostLoanMonitorMapper.select(postLoanMonitor);
        if (postLoanMonitors == null || postLoanMonitors.size() == 0) { //没有当前时段对应的维护信息则插入
            postLoanMonitor
                .setPostLoanImplementResult(PostLoanEnums.ImplementResult.UNFINISH.getCode());
            zyPostLoanMonitorMapper.insertSelective(postLoanMonitor);
        }
    }


    /**
     * 贷后状态的进件  如果在首次之后贷后维护时间周期内，需要检测生成贷后维护
     *
     * @param appMonitor 贷后的进件和产品客户信息集合
     * @return 贷后监控记录
     */
    @Nullable
    private ZyPostLoanMonitor getAfterPostLoanMonitor(LocalDate currDate, AppMonitor appMonitor) {
        ZyPostLoanMonitor postLoanMonitor = new ZyPostLoanMonitor()
            .setApplicationId(appMonitor.getId())
            .setPostLoanImplementType(PostLoanEnums.ImplementType.VISIT.getCode())
            .setPostLoanMonitorSetupType(PostLoanEnums.SetupType.AFTER_FIRST_LOAN.getCode());
        ProductPostLoan productLoanMonitorRules = appMonitor.getProductLoanMonitorRules();

        LocalDate loanTime = new LocalDate(appMonitor.getLoanTime()); //放款时间
        Integer firDay = onceTime(productLoanMonitorRules.getNormalWatchTime());
        Integer onceMonitorDay = onceTime(productLoanMonitorRules.getNormalFrequency()); //一个维护周期时间
        Integer LoanMonitorCount = (Days.daysBetween(loanTime, currDate).getDays() - firDay)
            / onceMonitorDay; //当前计算的是第几次该贷后
        if (LoanMonitorCount == 0) {
            return null;
        }
        Date createTime = loanTime.plusDays(firDay + LoanMonitorCount * onceMonitorDay).toDate();

        postLoanMonitor.setImplementTime(createTime)
            .setCreateTime(new Date())
            .setEndTime(new LocalDate(createTime).plusDays(onceMonitorDay).toDate());
        return postLoanMonitor;

    }


    /**
     * 贷后状态的进件  如果在首次贷后维护的生成时间内，需要检测生成首次贷后
     *
     * @param appMonitor 贷后的进件和产品客户信息集合
     * @return 贷后监控记录
     */
    private ZyPostLoanMonitor getFirstPostLoanMonitor(LocalDate currDate, AppMonitor appMonitor) {
        ZyPostLoanMonitor postLoanMonitor = new ZyPostLoanMonitor()
            .setApplicationId(appMonitor.getId())
            .setPostLoanImplementType(PostLoanEnums.ImplementType.VISIT.getCode());
        ProductPostLoan productLoanMonitorRules = appMonitor.getProductLoanMonitorRules();

        LocalDate loanTime = new LocalDate(appMonitor.getLoanTime()); //放款时间
        Integer firstMonitor = onceTime(productLoanMonitorRules.getNormalWatchTime());
        postLoanMonitor
            .setPostLoanMonitorSetupType(PostLoanEnums.SetupType.MAKE_LOANS_FIRST.getCode())
            .setImplementTime(loanTime.toDate())
            .setCreateTime(new Date())
            .setEndTime(loanTime.plusDays(firstMonitor).toDate());
        return postLoanMonitor;
    }

//    /**
//     * 贷后状态的进件在任意时间段都有一条属于该时间段的实地回访记录，查询当前时间段的实地回访记录
//     * @param appMonitor 贷后的进件和产品客户信息集合
//     * @return 实地回访记录
//     */
//    private ZyPostLoanMonitor getPostLoanSiteVisiable(LocalDate currDate, AppMonitor appMonitor) {
//        ZyPostLoanMonitor postLoanMonitor = new ZyPostLoanMonitor()
//                .setApplicationId(appMonitor.getId())
//                .setPostLoanImplementType(PostLoanEnums.ImplementType.VISIT.getCode())
//                .setPostLoanMonitorSetupType(PostLoanEnums.SetupType.FIELD_VISIT.getCode()) ;
//        ProductPostLoan productLoanMonitorRules = appMonitor.getProductLoanMonitorRules();
//
//        //计算当前时间的实地回访记录的开始时间
//        LocalDate loanTime = new LocalDate(appMonitor.getLoanTime()) ;
//        Integer siteVisiable = onceTime(productLoanMonitorRules.getSiteVisitsrate());   //一次实地回访的周期
//        Integer advance = getLoanAdvanceTime(siteVisiable);
//        Integer siteVisiablCount = (Days.daysBetween(loanTime,currDate).getDays() + advance )  / siteVisiable;
//
//        postLoanMonitor.setCreateTime(byPass(loanTime.plusDays(siteVisiablCount * siteVisiable),getOrganizationId(appMonitor)));
//        return postLoanMonitor;
//    }


    /**
     * 获得分批读取贷后状态进件数据的页数
     *
     * @return 分批进件的页数
     */
    private int getLoanApplicationPageCount() {
        Application application = new Application();
        application.setApplicationStatus(ApplicationStatusEnum.IS_SIGNED.getType());
        int total = applicationService.selectCount(application);
        int pageCount = total / PAGE_SIZE;
        if (total % PAGE_SIZE > 0) {
            pageCount++;
        }
        return pageCount;
    }


    /**
     * 根据贷后/逾期维护频率类型返回维护一次时间
     *
     * @param loanMonitorTimeType 维护频率类型
     * @return 维护一次毫秒时长
     */
    private Integer onceTime(int loanMonitorTimeType) {
        switch (loanMonitorTimeType) {
            case ProductPostLoan.IN_DAY:
                return ConstantTime.ONE_DAY;
            case ProductPostLoan.IN_WEEK:
                return ConstantTime.ONE_WEEK;
            case ProductPostLoan.IN_HANF_MONTH:
                return ConstantTime.HALF_MONTH;
            case ProductPostLoan.IN_ONE_MONTH:
                return ConstantTime.ONE_MONTH;
            case ProductPostLoan.IN_THREE_MONTH:
                return ConstantTime.THREE_MONTH;
            case ProductPostLoan.IN_SIX_MONTH:
                return ConstantTime.SIX_MONTH;
            default:
                return 0;
        }
    }


}
